from datetime import datetime
import time
import os
import asyncio
import pyautogui
import qasync
from PySide6.QtCore import QObject, Slot
from PySide6.QtWidgets import QMessageBox
from PySide6.QtGui import QPixmap

from src.models.recognition_model import RecognitionModel
from src.views.main_window import MainWindowView
from src.utils.image_processor import ImageProcessor
from src.utils.image_recognition import ImageRecognizer
from src.utils.screenshot import ScreenshotUtil
from src.utils.style_manager import StyleManager
from src.utils.resource_helper import get_resource_path  # 导入资源加载函数


class RecognitionController(QObject):
    """识别控制器类，处理业务逻辑"""

    def __init__(self, model: RecognitionModel, view: MainWindowView):
        super().__init__()
        self.model = model
        self.view = view
        
        # 异步任务取消标志
        self.cancellation_flag = False
        # 识别状态标志
        self.is_recognizing = False
        
        # 连接视图信号
        self._connect_signals()

    def _connect_signals(self):
        """连接视图信号到控制器槽函数"""
        self.view.capture_screen_signal.connect(self._on_capture_screen)
        self.view.start_recognition_signal.connect(self._on_start_recognition)
        self.view.stop_recognition_signal.connect(self._on_stop_recognition)
        self.view.clear_results_signal.connect(self._on_clear_results)
        
        # 使用qasync处理异步槽函数
        self.view.save_results_signal.connect(
            lambda: qasync.asyncio.create_task(self._on_save_results())
        )
        
        self.view.show_settings_signal.connect(self._on_show_settings)
        self.view.change_match_method_signal.connect(self._on_change_match_method)
        self.view.change_threshold_signal.connect(self._on_change_threshold)
        self.view.change_click_mode_signal.connect(self._on_change_click_mode)
        self.view.template_checkbox_toggled_signal.connect(
            self._on_template_checkbox_toggled
        )
        self.view.change_print_mode_signal.connect(self._on_change_print_mode)
        # 添加结果图生成模式变更信号连接
        if hasattr(self.view, 'change_result_image_mode_signal'):
            self.view.change_result_image_mode_signal.connect(self._on_change_result_image_mode)

    @Slot()
    def _on_capture_screen(self):
        """截图处理"""
        print("接收到截图信号")
        StyleManager.debug_print("接收到截图信号")
        
        try:
            # 使用qasync安全地启动异步任务
            qasync.asyncio.create_task(self._capture_screen_async())
        except Exception as e:
            StyleManager.debug_print(f"创建截图异步任务失败: {str(e)}")
            self.view.show_status_message(f"创建截图异步任务失败: {str(e)}")

    async def _capture_screen_async(self):
        """异步截图操作"""
        try:
            self.view.show_status_message("请选择截图区域...")
            
            # 使用区域截图
            result = await ScreenshotUtil.capture_screen_async(
                region=True, 
                temp_dir=self.model.temp_dir
            )
            
            if result:
                temp_file, pixmap, rect = result
                
                # 保存到模型
                if rect:
                    # 保存截图左上角坐标和宽高
                    self.model.update_image(temp_file, rect.x(), rect.y(), rect.width(), rect.height())
                    StyleManager.debug_print(f"保存截图区域: ({rect.x()}, {rect.y()}, {rect.width()}, {rect.height()})")
                
                # 更新界面
                if temp_file and pixmap and not pixmap.isNull():
                    file_info = os.path.getsize(temp_file) / 1024  # KB
                    info_text = (
                        f"图片信息:\n"
                        f"尺寸: {pixmap.width()} x {pixmap.height()}\n"
                        f"路径: {temp_file}\n"
                        f"大小: {file_info:.2f} KB"
                    )
                    self.view.update_image_preview(pixmap, info_text)
                    self.view.show_status_message("截图完成，可以开始识别")
                else:
                    self.view.show_status_message("截图失败，无法获取图像")
            else:
                self.view.show_status_message("用户取消了截图选择")
            
        except Exception as e:
            StyleManager.debug_print(f"截图过程中发生错误: {str(e)}")
            self.view.show_status_message(f"截图过程中发生错误: {str(e)}")

    @Slot()
    def _on_start_recognition(self):
        """开始识别处理"""
        # 增加调试输出
        print("接收到开始识别信号")
        StyleManager.debug_print("接收到开始识别信号")
        
        # 如果正在识别中，直接返回
        if self.is_recognizing:
            return
            
        # 重置取消标志
        self.cancellation_flag = False
        # 设置识别状态为True
        self.is_recognizing = True
        
        # 检查是否有源图像
        if not self.model.current_image_path:
            self.view.show_message_box("警告", "请先选择截图区域", QMessageBox.Warning)
            self.is_recognizing = False
            return
            
        # 检查是否有选中的模板
        checked_templates = self.view.get_checked_templates()
        if not checked_templates:
            self.view.show_message_box("警告", "请至少选择一个模板图片", QMessageBox.Warning)
            self.is_recognizing = False
            return
            
        try:
            # 使用qasync安全地启动异步任务
            qasync.asyncio.create_task(self._start_recognition_async())
        except Exception as e:
            StyleManager.debug_print(f"创建识别异步任务失败: {str(e)}")
            self.view.show_status_message(f"创建识别异步任务失败: {str(e)}")
            self.is_recognizing = False

    async def _start_recognition_async(self):
        """异步识别实现"""
        try:
            # 更新状态
            self.view.show_status_message("开始图像识别流程...")
            
            # 检查取消标志
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
            
            # 验证图像有效性
            is_valid = await ImageRecognizer.is_valid_image_async(
                self.model.current_image_path
            )
            
            if not is_valid:
                self.view.show_message_box(
                    "警告", 
                    f"图片无效或已损坏: {self.model.current_image_path}",
                    QMessageBox.Warning
                )
                return
                
            # 如果已取消，退出
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
                
            # 获取选中的模板
            active_templates = []
            template_names = {}
            
            for template_path, template_label in self.view.get_checked_templates():
                # 检查取消标志
                if self.cancellation_flag or not self.is_recognizing:
                    self.view.show_status_message("识别已取消")
                    return
                    
                # 模板路径已在视图层通过get_resource_path处理，直接使用
                if await ImageRecognizer.is_valid_image_async(template_path):
                    active_templates.append(template_path)
                    template_names[template_path] = template_label
            
            # 检查取消标志
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
                
            # 执行识别
            self.view.show_status_message("正在进行图像识别...")
            
            results = await ImageRecognizer.recognize_multiple_templates_async(
                self.model.current_image_path,
                active_templates,
                self.model.current_method,
                self.model.match_threshold,
                template_names
            )
            
            # 如果已取消，退出
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
                
            # 保存结果到模型
            self.model.update_recognition_results(results)
            
                
            # 处理识别结果
            await self._process_recognition_results(results)
            
        except Exception as e:
            StyleManager.debug_print(f"识别过程中发生错误: {str(e)}")
            self.view.show_status_message(f"识别过程中发生错误: {str(e)}")
            
        finally:
            # 设置识别状态为False
            self.is_recognizing = False

    async def _process_recognition_results(self, results):
        """处理识别结果"""
        # 检查取消标志
        if self.cancellation_flag or not self.is_recognizing:
            self.view.show_status_message("识别已取消")
            return
            
        if not results:
            # 未找到结果
            self.view.update_recognition_results("未找到匹配的模板", None)
            self.view.show_status_message("未找到匹配")
            
            try:
                # 检查取消标志
                if self.cancellation_flag or not self.is_recognizing:
                    self.view.show_status_message("识别已取消")
                    return
                    
                # 使用异步方式执行pyautogui操作
                await asyncio.get_event_loop().run_in_executor(None, lambda: pyautogui.press('v'))
                StyleManager.debug_print("未找到结果，发送V键盘事件")
                
                # 检查取消标志
                if self.cancellation_flag or not self.is_recognizing:
                    self.view.show_status_message("识别已取消")
                    return
                    
                # 等待一小段时间后自动重新截图并识别
                await asyncio.sleep(2)
            
                # 自动重新截图并识别
                if not self.cancellation_flag and self.is_recognizing:
                    # 使用之前的截图区域自动截取新的截图
                    await self._auto_capture_and_recognize()
            
            except Exception as e:
                StyleManager.debug_print(f"发送V键盘事件或自动重新截图过程中出错: {e}")    
                return
            
            return  # 结束处理
            
        # 找到匹配结果，生成结果文本
        result_text = ""
        click_points_text = "点击位置:\n"
        
        # 处理每个匹配结果
        for i, result in enumerate(results):
            # 检查取消标志
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
                
            # 打印详细匹配信息
            StyleManager.debug_print(
                f"================ 第{i+1}个匹配结果 ===============\n"
                f"模板名称: {result.template_name}\n"
                f"匹配度: {result.confidence:.4f}\n"
                f"颜色匹配: {result.color_match:.4f}\n"
                f"匹配位置: ({result.top_left[0]}, {result.top_left[1]})\n"
                f"模板尺寸: {result.width}x{result.height}\n"
                f"模板路径: {result.template_path}\n"
                f"源图像路径: {result.source_path}\n"
                "============================================"
            )
                
            confidence_text = f"匹配度: {result.confidence:.2f}"
            color_match_text = f"颜色匹配: {result.color_match:.2f}"
            position_text = f"位置: ({result.top_left[0]}, {result.top_left[1]})"
            size_text = f"尺寸: {result.width}x{result.height}"
            
            # 计算中心点坐标
            center_x_img = result.top_left[0] + result.width // 2
            center_y_img = result.top_left[1] + result.height // 2
            
            # 计算屏幕上的实际坐标
            screen_x = self.model.screenshot_x + center_x_img
            screen_y = self.model.screenshot_y + center_y_img
            
            
            if i > 0:
                result_text += "\n\n"
                
            result_text += f"模板: {result.template_name}\n{confidence_text}\n{color_match_text}\n{position_text}\n{size_text}"
            result_text += f"\n图片内坐标: ({center_x_img}, {center_y_img})"
            result_text += f"\n屏幕坐标: ({screen_x}, {screen_y})"
            click_points_text += f"- 模板 {result.template_name}: ({screen_x}, {screen_y})\n" 
                
            try:
                # 发送鼠标点击事件 - 使用异步方式执行
                await asyncio.get_event_loop().run_in_executor(
                    None, 
                    lambda: pyautogui.click(screen_x, screen_y)
                )
                StyleManager.debug_print(f"已在屏幕位置({screen_x}, {screen_y})发送点击事件")
            except Exception as e:
                StyleManager.debug_print(f"发送鼠标点击事件出错: {e}")
        
        # 检查取消标志
        if self.cancellation_flag or not self.is_recognizing:
            self.view.show_status_message("识别已取消")
            return
            
        # 添加点击位置总结
        if results:
            # 点击所有结果，提供详细的点击信息
            result_text += f"\n\n已点击所有{len(results)}个结果:\n{click_points_text}"
        else:
            result_text += f"\n\n{click_points_text}"
            
        # 检查取消标志
        if self.cancellation_flag or not self.is_recognizing:
            self.view.show_status_message("识别已取消")
            return
            
        # 根据配置决定是否生成结果图像
        if results and self.model.enable_result_image:
            output_path = os.path.join(self.model.temp_dir, "recognition_result.png")
            result_img = await ImageRecognizer.draw_recognition_results_async(
                self.model.current_image_path, results, output_path
            )
            
            if result_img is not None:
                result_pixmap = QPixmap(output_path)
                self.view.update_recognition_results(result_text, result_pixmap)
                self.view.show_status_message("识别完成")
            else:
                self.view.update_recognition_results(result_text, None)
                self.view.show_status_message("识别完成，但无法生成结果图像")
        else:
            # 不生成结果图像，只显示文本结果
            self.view.update_recognition_results(result_text, None)
            self.view.show_status_message("识别完成")
            
        # 所有结果处理完毕后，发送V键盘事件
        try:
            # 使用异步方式执行pyautogui操作
            await asyncio.get_event_loop().run_in_executor(None, lambda: pyautogui.press('v'))
            StyleManager.debug_print("已发送V键盘事件")
            self.view.show_status_message("已点击所有结果并发送V键盘事件，正在准备下一轮...", 1500)
            
            # 检查取消标志
            if self.cancellation_flag or not self.is_recognizing:
                self.view.show_status_message("识别已取消")
                return
                
            # 等待一小段时间后自动重新截图并识别
            await asyncio.sleep(2)
            
            # 自动重新截图并识别
            if not self.cancellation_flag and self.is_recognizing:
                # 使用之前的截图区域自动截取新的截图
                await self._auto_capture_and_recognize()
            
        except Exception as e:
            StyleManager.debug_print(f"发送V键盘事件或自动重新截图过程中出错: {e}")

    @Slot()
    def _on_stop_recognition(self):
        """停止识别进程"""
        # 增加调试输出
        print("接收到停止识别信号")
        StyleManager.debug_print("接收到停止识别信号")
        
        # 如果没有在识别中，直接返回
        if not self.is_recognizing:
            StyleManager.debug_print("当前没有正在进行的识别流程")
            self.view.show_status_message("当前没有正在进行的识别流程")
            return
            
        # 设置取消标志
        self.cancellation_flag = True
        # 立即更新识别状态
        self.is_recognizing = False
        
        self.view.show_status_message("已停止识别流程")
        StyleManager.debug_print("识别流程已取消")

    @Slot()
    def _on_clear_results(self):
        """清空识别结果"""
        # 清空模型数据
        self.model.current_image_path = None
        self.model.recognition_results = []
        
        # 清空UI
        self.view.update_image_preview(QPixmap(), "图片信息:\n尺寸: \n路径: \n大小: ")
        self.view.update_recognition_results(
            '请选择截图区域并点击"开始识别"按钮',
            QPixmap()
        )
        self.view.show_status_message("结果已清除")
        
        # 清理缓存
        ImageProcessor.clear_cache()

    @Slot()
    async def _on_save_results(self):
        """保存识别结果"""
        if not self.model.recognition_results:
            self.view.show_message_box("警告", "没有可保存的识别结果", QMessageBox.Warning)
            return
            
        # 获取保存路径
        save_path = self.view.get_save_file_path(
            "保存结果图像", 
            "图片文件 (*.png *.jpg *.jpeg)"
        )
        
        if not save_path:
            return
            
        # 使用异步版本保存结果图像
        try:
            # 显示正在保存的状态信息
            self.view.show_status_message("正在保存结果图像...")
            
            # 异步保存结果图像
            result_img = await ImageRecognizer.draw_recognition_results_async(
                self.model.current_image_path,
                self.model.recognition_results,
                save_path
            )
            
            if result_img is not None:
                self.view.show_status_message(f"结果图像已保存到: {save_path}")
            else:
                self.view.show_message_box("错误", "保存结果图像失败", QMessageBox.Critical)
        except Exception as e:
            StyleManager.debug_print(f"保存图像时发生错误: {str(e)}")
            self.view.show_message_box("错误", f"保存结果图像失败: {str(e)}", QMessageBox.Critical)

    @Slot()
    def _on_show_settings(self):
        """显示设置对话框"""
        # 临时禁用设置对话框功能
        self.view.show_status_message("设置功能暂时不可用，修复中...")
        return

    @Slot(str)
    def _on_change_match_method(self, method: str):
        """更改匹配方法"""
        self.model.current_method = method
        self.view.update_method_button_text(method, self.model.enable_print)

    @Slot(float)
    def _on_change_threshold(self, threshold: float):
        """更改匹配阈值"""
        self.model.match_threshold = threshold

    @Slot(bool)
    def _on_change_click_mode(self, click_first_only: bool):
        """更改点击模式 - 该方法已弃用，保留接口兼容性"""
        # 在状态栏显示信息
        self.view.show_status_message(f"已配置为点击所有识别结果", 3000)

    @Slot(bool)
    def _on_change_print_mode(self, enable_print: bool):
        """更改打印模式"""
        self.model.enable_print = enable_print
        self.view.update_method_button_text(self.model.current_method, enable_print)
        
    @Slot(bool)
    def _on_change_result_image_mode(self, enable_result_image: bool):
        """更改结果图生成模式"""
        self.model.enable_result_image = enable_result_image
        # 如果视图有更新方法按钮的功能，则调用它
        self.view.update_method_button_text(
            self.model.current_method, 
            self.model.enable_print, 
            enable_result_image
        )

    @Slot(str, str, bool)
    def _on_template_checkbox_toggled(self, template_path, template_label, checked):
        """处理模板选择变化"""
        # 增加调试输出
        StyleManager.debug_print(f"模板选择变化: {template_label} - {template_path}, 状态: {'选中' if checked else '未选中'}")

    async def _auto_capture_and_recognize(self):
        """自动截取当前区域的截图并启动识别处理"""
        try:
            # 首先检查取消标志
            if self.cancellation_flag or not self.is_recognizing:
                StyleManager.debug_print("识别已取消，终止自动截图和识别")
                return
                
            # 检查是否设置了截图区域坐标
            if self.model.screenshot_x is None or self.model.screenshot_y is None:
                StyleManager.debug_print("没有可用的截图区域坐标，无法自动截图")
                return
                
            self.view.show_status_message("自动截取区域并识别中...")
            
            # 获取上次截图区域的尺寸
            width, height = None, None
            
            # 优先使用已保存的宽高数据
            if hasattr(self.model, 'screenshot_width') and hasattr(self.model, 'screenshot_height'):
                if self.model.screenshot_width is not None and self.model.screenshot_height is not None:
                    width, height = self.model.screenshot_width, self.model.screenshot_height
                    StyleManager.debug_print(f"使用已保存的截图尺寸: {width}x{height}")
            
            # 如果没有保存宽高数据，则从图片获取
            if width is None or height is None:
                if not self.model.current_image_path or not os.path.exists(self.model.current_image_path):
                    StyleManager.debug_print("没有可用的原始截图，无法确定区域大小")
                    return
                    
                # 获取上一张截图的尺寸
                img_size = await ImageRecognizer.get_image_size_async(self.model.current_image_path)
                if not img_size:
                    StyleManager.debug_print("无法获取原始截图尺寸")
                    return
                    
                width, height = img_size
                StyleManager.debug_print(f"从图片获取的截图尺寸: {width}x{height}")
            
            # 使用之前的截图区域坐标和尺寸
            x, y = self.model.screenshot_x, self.model.screenshot_y
            
            # 执行区域截图
            temp_file = os.path.join(self.model.temp_dir, f"auto_screenshot_{int(time.time())}.png")
            
            # 使用异步方式执行截图操作
            screenshot_result = await ScreenshotUtil.capture_region_async(
                x, y, width, height, temp_file
            )
            
            if screenshot_result:
                # 更新模型中的图像路径
                self.model.update_image(temp_file, x, y, width, height)
                
                # 更新界面
                pixmap = QPixmap(temp_file)
                if not pixmap.isNull():
                    file_info = os.path.getsize(temp_file) / 1024  # KB
                    info_text = (
                        f"图片信息:\n"
                        f"尺寸: {pixmap.width()} x {pixmap.height()}\n"
                        f"路径: {temp_file}\n"
                        f"大小: {file_info:.2f} KB"
                    )
                    self.view.update_image_preview(pixmap, info_text)
                    
                    # 启动识别过程
                    StyleManager.debug_print("自动截图完成，开始识别")
                    
                    # 检查是否已取消
                    if self.cancellation_flag:
                        StyleManager.debug_print("操作已取消")
                        return
                        
                    # 检查选中的模板
                    checked_templates = self.view.get_checked_templates()
                    if not checked_templates:
                        StyleManager.debug_print("没有选中的模板，无法继续识别")
                        return
                        
                    # 异步执行识别
                    active_templates = []
                    template_names = {}
                    
                    for template_path, template_label in checked_templates:
                        if await ImageRecognizer.is_valid_image_async(template_path):
                            active_templates.append(template_path)
                            template_names[template_path] = template_label
                    
                    # 执行识别
                    self.view.show_status_message("正在进行图像识别...")
                    
                    results = await ImageRecognizer.recognize_multiple_templates_async(
                        self.model.current_image_path,
                        active_templates,
                        self.model.current_method,
                        self.model.match_threshold,
                        template_names
                    )
                    
                    # 如果已取消，退出
                    if self.cancellation_flag:
                        self.view.show_status_message("识别已取消")
                        return
                        
                    # 保存结果到模型
                    self.model.update_recognition_results(results)
                    
                    # 处理识别结果
                    await self._process_recognition_results(results)
                else:
                    StyleManager.debug_print("自动截图失败，无法获取有效图像")
            else:
                StyleManager.debug_print("自动截图失败")
                
        except Exception as e:
            StyleManager.debug_print(f"自动截图与识别过程中发生错误: {str(e)}") 

    def _set_buttons_enabled(self, enabled: bool = True):
        """手动设置所有按钮和模板复选框的启用/禁用状态"""
        # 设置所有按钮状态
        self.view.region_screenshot_btn.setEnabled(enabled)
        self.view.start_btn.setEnabled(enabled)
        self.view.stop_btn.setEnabled(enabled)
        self.view.clear_btn.setEnabled(enabled)
        self.view.save_btn.setEnabled(enabled)
        self.view.settings_btn.setEnabled(enabled)
        
        # 设置所有复选框状态
        for checkbox in self.view.checkboxes:
            checkbox.setEnabled(enabled)
            # 确保更新外观
            checkbox.update() 